/*******************************************************************************
 * This file is part of blueprint4j www.blueprint4j.org.
 * 
 *     blueprint4j is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     blueprint4j is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with blueprint4j. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package blueprint4j.db;

import java.net.ServerSocket;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;

import blueprint4j.utils.Log;
import blueprint4j.utils.Settings;

public class DBTools {
    public static final String CONNECTIONPOOL_DEFAULT = "DEFAULT";
    private static SettingsStoreDB settings_store = null;
    private static String server_id=null;
    public static String IDNONE="IDNONE";
    
    public static final boolean SETUP_DATABASE = Settings.getBoolean("database.init.setup",true);
    
    // only one server registers with database to update and maintain tables
    private static Object maintain_database_sync = new Object();
    private static Boolean do_i_maintain_database = null;
    private static ServerSocket server_socket = null;
    // keep a local connection for each database type
    private static Hashtable connection_pool = new Hashtable();
    private static Hashtable local_connection = new Hashtable();
    
    private static DBConnection connection = null;
    
    public static SettingsStoreDB getSettingsStore() {
        return settings_store;
    }
    
    public static void setConnectionPool(ConnectionPool pool,String poolname)
    throws SQLException {
        if (!connection_pool.containsKey(pool)) {
            connection_pool.put(poolname,pool);
            DBConnection dbcon = getLC(poolname);
            if (SETUP_DATABASE) {
                dbcon.getDataBaseUtils().setupDatabaseServer(dbcon);
            }
        }
    }
    
    private static ConnectionPool getConnectionPool(String poolname) {
        if (connection_pool.containsKey(poolname)) {
            return (ConnectionPool) connection_pool.get(poolname);
        }
        return null;
    }
    
    public static DBConnection getLocalConnection(String url)
    throws SQLException {
        if (local_connection.containsKey(url)) {
            return (DBConnection) local_connection.get(url);
        }
        return null;
    }
    
    public static DBConnection getLocalConnection(ConnectionPool pool)
    throws SQLException {
        DBConnection local = getLocalConnection(pool.getUrl());
        if (local == null) {
            DBConnection connection = pool.getConnection(false);
            connection.setAutoCommit(true);
            local_connection.put(pool.getUrl(),connection);
            return getLocalConnection(pool);
        } else {
            return local;
        }
    }
    
    public static DBConnection getLocalConnection(DBConnection reference)
    throws SQLException {
        DBConnection local = getLocalConnection(reference.getUrl());
        if (local == null) {
            DBConnection connection = reference.getNewInstance();
            connection.setAutoCommit(true);
            local_connection.put(reference.getUrl(),connection);
            return getLocalConnection(reference);
        } else {
            return local;
        }
    }
    
    static private DBConnection getDBConnection(String poolname)
    throws DataException, SQLException {
        if (getConnectionPool(poolname) != null) {
            return getConnectionPool(poolname).getConnection(true);
        }
        return null;
    }
    
    /**
     * Returns a new default connection
     */
    static public DBConnection getNDC()
    throws DataException, SQLException {
        return getDBConnection(CONNECTIONPOOL_DEFAULT);
    }
    
    static public DBConnection getNC(String CONNECTIONPOOL )
    throws DataException, SQLException {
        return getDBConnection(CONNECTIONPOOL);
    }
    
    public static DBConnection getDLC()
    throws SQLException {
        if (getConnectionPool(CONNECTIONPOOL_DEFAULT) != null) {
            return getLocalConnection(getConnectionPool(CONNECTIONPOOL_DEFAULT));
        } else {
            throw new DataException("NO DEFAULT CONNECTION POOL SETUP");
        }
    }
    
    /**
     * Returns the location connection referenced from Connection Pool CONNECTION_POOLNAME
     */
    public static DBConnection getLC(String CONNECTION_POOLNAME)
    throws SQLException {
        if (getConnectionPool(CONNECTION_POOLNAME) == null) {
            return null;
        }
        return getLocalConnection(getConnectionPool(CONNECTION_POOLNAME));
    }
    
    static public String getServerId() {
        try {
            return ServerInformation.getServerId(getDLC());
        } catch (Exception exception) {
            exception.printStackTrace();
            Log.critical.out(exception);
        }
        return null;
    }
    
    static public boolean serverIDNotDefined(){
        return IDNONE.equals(getServerId());
    }
    
    static public void setServerId(String p_server_id) {
        server_id=p_server_id;
        Settings.setString("db_tools.server_id",server_id);
    }
    
    
    public static boolean hasDeafaultCP() {
        return connection_pool.containsKey(CONNECTIONPOOL_DEFAULT);
    }
    
    public static boolean hashLocalConnectionBeenInitialized() {
        return !(connection == null);
    }
    
    public static boolean doesTableExist(DBConnection dbcon,String table_name) {
        try {
            Statement smt = dbcon.createStatement();
            try {
                smt.executeQuery("select * from "+table_name);
                return true;
            } finally {
                smt.close();
            }
        } catch (SQLException sqle) {
            return false;
        }
    }
    
    public static void dropTable(DBConnection dbcon,String tabname)
    throws SQLException {
        Statement smt = dbcon.createStatement();
        try {
            smt.execute("drop table " + tabname);
        } finally {
            smt.close();
        }
    }
    
}

